home *** CD-ROM | disk | FTP | other *** search
/ Magnum One / Magnum One (Mid-American Digital) (Disc Manufacturing).iso / d12 / v9n03.arc / CHKFILE.ASM < prev    next >
Assembly Source File  |  1990-01-12  |  63KB  |  1,022 lines

  1.          PAGE  60,132
  2.          TITLE CHKFILE - High performance file checker
  3.          SUBTTL  General program description and use of common storage
  4. ; ----------------------------------------------------------------------------;
  5. ;        CHKFILE - characterize files by check values, time, date and size.   ;
  6. ; ----------------------------------------------------------------------------;
  7. ;   CHKFILE 1.0 ■ PCDATA TOOLKIT Copyright (c) 1990 Ziff Communications Co.   ;
  8. ;                   PC Magazine ■ Wolfgang Stiller                            ;
  9. ;                                                                             ;
  10. ;-----------------------------------------------------------------------------;
  11.  
  12. ;-----------------------------------------------------------------------------;
  13. ;Purpose:                                                                     ;
  14. ;        CHKFILE will read files and then characterize them with unique       ;
  15. ;        check values, update date, update time and file size.  This          ;
  16. ;        data can be used to validate file integrity by determining if        ;
  17. ;        the file has undergone any changes. The output can be                ;
  18. ;        redirected to a file which may be compared later using program       ;
  19. ;        CFcomp.                                                              ;
  20. ;-----------------------------------------------------------------------------;
  21. ;Syntax:                                                                      ;
  22. ;                                                                             ;
  23. ;CHKFILE [d:] [path] filename [/D] [/I:aa] [/T] [/1] [/2]                     ;
  24. ;                                                                             ;
  25. ;      filename  specifies the files to be read and checked. Wild card chars  ;
  26. ;                 such as * or ? can be used as well as a drive or directory. ;
  27. ;       "/D"      Display directory entries as well as regular files          ;
  28. ;       "/I:aa"   Ignore files beginning with characters aa (must be 2 chars).;
  29. ;       "/T"      Generate cumulative total file check values for all files   ;
  30. ;                 checked (both check value 1 and value 2).                   ;
  31. ;       "/1"      Utilizes an alternate algorithm for check value 1.          ;
  32. ;       "/2"      Utilizes an alternate algorithm for check value 2.          ;
  33. ;                                                                             ;
  34. ;  CHKFILE entered with no filename will produce a display of the correct     ;
  35. ;  syntax.                                                                    ;
  36. ;-----------------------------------------------------------------------------;
  37. ;Remarks:                                                                     ;
  38. ;   CHKFILE has been specifically designed for high speed operation using a   ;
  39. ;   minimal of resources. It will run on any DOS PC with at least 64K free    ;
  40. ;   memory. CHKFILE will read all files independent of whether they have      ;
  41. ;   the hidden or the system attribute set.   CHKFILE produces a report       ;
  42. ;   line for each file (and optionally  directory) matching the primary       ;
  43. ;   file specification.  CHKFILE will report for each file in the current     ;
  44. ;   or specified directory the following information: File or directory       ;
  45. ;   name, check value 1, check value 2, file size, and the DOS date and       ;
  46. ;   time of last update. This information is  written to the DOS standard     ;
  47. ;   output device and may be redirected to a file.  The check values and      ;
  48. ;   the file size are displayed as hex digits, for compactness of output.     ;
  49. ;                                                                             ;
  50. ;   If CHKFILE encounters an error related to misuse of its parameters, it    ;
  51. ;   will produce an error message followed by a beep and a request for a      ;
  52. ;   key press.  After a key press, it will display a description of the       ;
  53. ;   correct syntax.                                                           ;
  54. ;                                                                             ;
  55. ;   Both check values utilize a very high speed algorithm for computation.    ;
  56. ;   Check value 1 is an arithmetic sum (or difference for /1) of all bytes    ;
  57. ;   in each file being checked. Check value 2 utilizes a high speed hash      ;
  58. ;   type algorithm which utilizes circular shifts and the exclusive or        ;
  59. ;   function to generate a unique 16 value which is dependent not only on     ;
  60. ;   the value of each byte in the file, but the order of those values. If     ;
  61. ;   "/1" or "/2" are specified, either or both of these algorithms can be     ;
  62. ;   changed. This change is done at initialization time, so that the speed    ;
  63. ;   of the check value computation is not affected by these options. This     ;
  64. ;   capability exists to make it more difficult for a destructive program     ;
  65. ;   to modify a file and then to find and patch the CHKFILE output file to    ;
  66. ;   mask this change. Since this protection is only minimal, it is best to    ;
  67. ;   store the file containing CHKFILE's output  off-line on a floppy.         ;
  68. ;                                                                             ;
  69. ;   It is recommended that the "/T" option be used anytime CHKFILE is         ;
  70. ;   checking more than a single file. "/T" will generate a totals line as     ;
  71. ;   the last line of output.  This line will contain a cumulative check       ;
  72. ;   value 1 and check value 2.  Specifying the /T option makes it easy to     ;
  73. ;   "eyeball" CHKFILE reports to see if any files have changed by comparing   ;
  74. ;   the totals lines on two reports.  The totals line also helps CFcomp to    ;
  75. ;   give you more information.  If you have renamed some files but made no    ;
  76. ;   other changes, CFcomp can recognize this.  CHKFILE can be used several    ;
  77. ;   ways.  One possibility is to use it directly to check files, and then     ;
  78. ;   manually record the check values and file size for later comparison.      ;
  79. ;   This may be useful when sending or transmitting files, to verify that     ;
  80. ;   the file was not damaged enroute.  Another possibility is to redirect     ;
  81. ;   the output of CHKFILE. For example:                                       ;
  82. ;                   "CHKFILE *.* /D /T /I:$$ >$$A",                           ;
  83. ;   will check all files and subdirectory entries in the current directory,   ;
  84. ;   produce a totals line, ignore all file names beginning with $$ and        ;
  85. ;   write the output to a file called $$A.  This command can be repeated at   ;
  86. ;   a later date.  By using CFcomp to compare the two files containing        ;
  87. ;   redirected output, a report will be produced showing all changes to any   ;
  88. ;   of the files in that directory.                                           ;
  89. ;                                                                             ;
  90. ;   If the entry being checked is a directory entry, CHKFILE will report:     ;
  91. ;   "Dir."  in the check value fields.                                        ;
  92. ;                                                                             ;
  93. ;   If CHKFILE was unable to open a file in order to read it, it will         ;
  94. ;   report "Open fail" in the check value fields.                             ;
  95. ;                                                                             ;
  96. ;   If CHKFILE failed to read a file, "Read fail" will appear in the check    ;
  97. ;   value fields for that file.  If this happens it is normally due to        ;
  98. ;   insufficient file handles (increase the FILES=nnnn number in your         ;
  99. ;   CONFIG.SYS file) or due to failed access on a network.                    ;
  100. ;                                                                             ;
  101. ;  CHKFILE will return the following DOS ERRORLEVELs:                         ;
  102. ;  00 - Normal completion - at least one file was reported.                   ;
  103. ;  04 - No files were checked. Either none match the filespec or all          ;
  104. ;       matched files were ignored by the /I parameter.                       ;
  105. ;  08 - Normal processing except open or I/O error was detected on a file.    ;
  106. ;  64 - (40H) Program failure due to invalid path or drive specified.         ;
  107. ; 128 - (80H) Syntax error or missing parameters on program initiation.       ;
  108. ;                                                                             ;
  109. ;-----------------------------------------------------------------------------;
  110. ;  CHKFILE will report for each file in the current or specified directory    ;
  111. ;  the following information:                                                 ;
  112. ;    Name of file, 16 bit check sum (0 to 64K), 16 bit XOR result, DOS time   ;
  113. ;    and date stamps of the file, and file size in hex bytes                  ;
  114. ; Format for report lines:                                                    ;
  115. ;         1         2         3         4         5         6                 ;
  116. ;123456789012345678901234567890123456789012345678901234567890                 ;
  117. ;File Name + Check Check  File    Update   Update                             ;
  118. ;Extension:  Val1: Val2:  Size:   Date:    Time:                              ;
  119. ;------------ ---- ---- -------- -------- --------                            ;
  120. ;filename.ext xxxx yyyy FileSize mm/dd/yy hh:mm:ss                            ;
  121. ;     1        1    1      1         1        1                               ;
  122. ;     1        1    1      1         1        1__Time of last file update     ;
  123. ;     1        1    1      1         1__________ Date of last update          ;
  124. ;     1        1    1      1____________________ Size of file in bytes-hex    ;
  125. ;     1        1    1___________________________ Check value 1 (SUM) -HEX     ;
  126. ;     1        1________________________________ Check value 2 (XOR) -HEX     ;
  127. ;     1_________________________________________ Name of the file             ;
  128. ;                                                                             ;
  129. ; ----------------------------------------------------------------------------;
  130. ;                                                                             ;
  131. ;  Total record length for output file (DSP_REC) is 51 bytes.                 ;
  132. ;                                                                             ;
  133. ;  ** See DSP_REC definition for detail on field descriptions **              ;
  134. ;                                                                             ;
  135. ; Check value 1 - Is a modified check sum or difference - 16 bits.            ;
  136. ; Check value 2 - Is a modified cumulative XOR of each character in           ;
  137. ;                 file - 16 bits.                                             ;
  138. ; ----------------------------------------------------------------------------;
  139. ;Sample output:                                                               ;
  140. ;                                                                             ;
  141. ;CHKFILE 1.0 ■ PCDATA TOOLKIT (c) 1990 Ziff Communications Co.                ;
  142. ;PC Magazine ■ Wolfgang Stiller checking: *.*                                 ;
  143. ;                                                                             ;
  144. ;File Name + Check Check  File    Update   Update                             ;
  145. ;Extension:  Val1: Val2:  Size:   Date:    Time:                              ;
  146. ;----------   ---- ----   -----   ------   ------                             ;
  147. ;IBMBIO.COM   03E6 A98D     5654 03/18/87 12:00:00                            ;
  148. ;IBMDOS.COM   FC1B 941D     75CF 03/17/87 12:00:00                            ;
  149. ;ERRORFIL.TST Read fail    75512 04/01/89 10:11:10                            ;
  150. ;DOS          Dir.               12/01/87 23:33:48                            ;
  151. ;Total======> 1DFF F677                                                       ;
  152. ;                                                                             ;
  153. ;Notes: CHKFILE always displays the filespec it is checking. In this          ;
  154. ;       case it is checking "*.*" all files.  The final line of output:       ;
  155. ;       "Total======>" indicates that the /T parameter was specified.         ;
  156. ;       The presence of directory DOS indicates the /D parameter was          ;
  157. ;       specified.  IBMBIO.COM and IBMDOS.COM are two hidden system           ;
  158. ;       files. These illustrate normal output from CHKFILE. CHKFILE was       ;
  159. ;       unable to read ERRORFIL.TST.  It was however able to display the      ;
  160. ;       information from the directory concerning this file.                  ;
  161. ; ----------------------------------------------------------------------------;
  162.  
  163. ;---------------------------------------------------------------;
  164. ; Constants:                                                    ;
  165. ;---------------------------------------------------------------;
  166. BOX         EQU    254                    ;Small box character code
  167. CR          EQU    0Dh
  168. LF          EQU    0Ah
  169. CRLF        EQU    0A0Dh                  ;Carriage return line feed.
  170. REP_Rec_Len EQU    51                     ;Length of display record
  171.  
  172. CSEG    SEGMENT
  173.         ASSUME  CS:CSEG, DS:CSEG, ES:CSEG, SS:CSEG
  174. ;---------------------------------------------------------------;
  175. ; D T A description  (data transfer area):                      ;
  176. ;---------------------------------------------------------------;
  177.         ORG     80h                       ;DTA and parameter line in PSP
  178. DTA_start   DB  21 DUP (?)                ; Reserved part of DTA + parm start
  179. DTA_F_attr  DB  ?                         ; File attribtute
  180. DTA_F_time  DW  ?                         ; File time
  181. DTA_F_date  DW  ?                         ;File date
  182. DTA_FS_lowr DW  ?                         ;File size lower part
  183. DTA_FS_HIr  DW  ?                         ;File size upper part
  184. DTA_F_name  DB  13 DUP(?)                 ;File name and extension
  185.  
  186.  
  187.         SUBTTL  Main program
  188. ;******************************************************************************;
  189. ;**   Main program begins here -CHKFILE-                                     **;
  190. ;******************************************************************************;
  191.         ORG     100h                      ; THIS IS A COM TYPE PROGRAM
  192. CHKFILE:
  193.         CALL    Parse_parms_Displ_Header  ;Parse cmdline paramters + prnt header
  194.                                           ; + find first match on file name
  195. ; ----------------------------------------------------------------------------;
  196. ; F O R M A T    F I L E    I N F O                                           ;
  197. ; Process information extracted from the directory entries (the DTA)          ;
  198. ; ----------------------------------------------------------------------------;
  199. ; GENERAL ALGORITHM:                                                          ;
  200. ; 1) Check if this is a .. or . directory or a file to ignore (/I:xx)         ;
  201. ;    If its to be ignored, go try to do another FIND NEXT generic match.      ;
  202. ; 2) Extract file name, size, date and time from the DTA.                     ;
  203. ; 3) IF its a directory, indicate by placing DIR. in the check value1 field.  ;
  204. ;    otherwise the file will be opened and processed.                         ;
  205. ; ----------------------------------------------------------------------------;
  206. Format_File_Info:
  207. ;----------------------------------------------------------------------------;
  208. ; Check if this is a file name to ignore (the .. and . directories) or a file;
  209. ; beginning with xx from the "/I:xx" command line parameter.                 ;
  210. ;----------------------------------------------------------------------------;
  211.         MOV     SI, offset DTA_F_Name     ;Move FROM DTA file name field
  212.         MOV     AX,WORD PTR [SI]          ;load 1st 2 chars of this file name
  213.         CMP     AL,'.'                    ;Is it a "." or ".." directory?
  214.         JNE     Check_For_Ignore_files    ;  No, so check for ignore files
  215.         JMP     Find_Next_File            ;  Yes, it is so skip this file
  216. Check_For_Ignore_Files:
  217.         CMP     AX,Ignore_F_Name          ;Is this the file name to ignore?
  218.         JNE     Xtract_DTA_Info           ;  No, so go ahead + process this file
  219.         JMP     Find_Next_File            ;  Yes, so skip this file...
  220. ;----------------------------------------------------------------------------;
  221. ; Extract info from the DTA (data transfr area)                              ;
  222. ; Extract file name, size and update date and time.                          ;
  223. ;----------------------------------------------------------------------------;
  224. Xtract_DTA_Info:
  225.         MOV     Files_Found,'Y'           ;Indicate at least one file found
  226.         MOV     CX,12                     ;Scan 12 characters of filename
  227. ;               SI= offset DTA_F_Name     ;SI already contains loc of DTA_F_NAME
  228.         MOV     DI, offset REP_F_Name     ;Move to report record file name
  229.  
  230. Xfer_file_name:                           ;transfer filename from DTA to REP_rec
  231.         LODSB                             ;Load one byte from DTA for transfer
  232.         OR      AL,AL                     ;See if this=0 (end of file name)
  233.         JZ      Blank_fill                ;If end, then blank fill rest of name
  234.         STOSB                             ;Else store char in REPRec file name
  235.         LOOP    Xfer_file_name            ;continue until done
  236.         JMP     Short Format_f_size       ;Go and format file size for REPort
  237.  
  238. Blank_fill:                               ;blank fill remainder of file name
  239.         MOV     AL,' '
  240.         REP     STOSB                     ;Store remaining characters
  241.  
  242. ; --------------------------------------------------;
  243. ; Extract file size from DTA for display            ;
  244. ; --------------------------------------------------;
  245. Format_F_size:                            ;Format DTA's file size for output
  246.         MOV     DI,offset REP_F_Size      ;Display formatted file size
  247.         MOV     SI,offset DTA_FS_HIr+1    ;End of DTA file size area
  248.         MOV     CX,4                      ;process 4 bytes (2 words) file size
  249.         XOR     DX,DX                     ;DX=0 means only leading zeros so far
  250.  
  251. Get_byte_to_Hex_Convert:                  ;Conv each byte to 2 HEX ASCII digits
  252.         MOV     AH,BYTE PTR [SI]          ;Pick up char from end of DTA F size
  253.         CALL    Convert_Hex_ASCII         ;Convert 4 bit hex to ASCII displcode
  254.         DEC     SI                        ;Get prior byte in DTA file size
  255.         LOOP    Get_Byte_to_Hex_Convert   ;Do all four bytes
  256.  
  257. ; --------------------------------------------------;
  258. ; Extract file date from DTA for display            ;
  259. ; --------------------------------------------------;
  260.         MOV     AX,[DTA_F_date]           ;Date of last file update
  261. ;       date is in yyyyyyym mmmddddd format (year is offset from 1980)
  262.         MOV     DX,AX                     ;Save a copy of file date
  263.         MOV     BL,10                     ;Put 10 in BL for decimal conversion
  264. ;MONTH
  265.         MOV     CL,5                      ;Prepare to shift right 5 bits
  266.         ROR     AX,CL                     ;Move month to right of word
  267.         AND     AX,0Fh                    ;only month remains
  268.         MOV     DI,offset REP_F_MM        ;Point to month field in REP_rec
  269.         Call    Convert_Dec_ASCII         ;Convert 2 decimal digits to ASCII
  270.  
  271. ;DAY
  272.         MOV     AX,DX                     ;Restore copy of DTA date
  273.         AND     AX,1fh                    ;Extract day portion of date
  274.         MOV     DI,OFFSET REP_F_DD        ;Point to day field in REP rec
  275.         Call    Convert_Dec_ASCII         ;Convert 2 decimal digits to ASCII
  276.  
  277. ;YEAR
  278.         MOV     AX,DX                     ;Restore copy of DTA date
  279.         MOV     CL,7
  280.         ROL     AX,CL                     ;Bring year of date to right of AX
  281.         AND     AX,7Fh                    ;MASK off right 7 bits of YEAR
  282.         ADD     AX,80                     ;Year is years after 1980
  283.         CMP     AX,100                    ;Are we in the next century?
  284.         JB      Transfer_year             ;IF not go ahead and display YY
  285.         SUB     AX,100                    ;Otherwise adjust the year
  286. Transfer_year:
  287.         MOV     DI,OFFSET REP_F_YY        ;Point to year field in REP_REC
  288.         Call    Convert_Dec_ASCII         ;Convert 2 decimal digits to ASCII
  289.  
  290.  
  291. ; --------------------------------------------------;
  292. ; Extract file time from DTA for display            ;
  293. ; --------------------------------------------------;
  294.         MOV     AX,[DTA_F_time]           ;time of last file update
  295. ;       time is in hhhhhmmm mmmsssss format (seconds are 0-29 in 2 sec intervl)
  296.  
  297. ;HOURS
  298.         MOV     DX,AX                     ;Create a copy of the time
  299.         MOV     CL,5                      ;Shift for hour bits
  300.         ROL     AX,CL                     ;hours are on the right of AX
  301.         AND     AX,1Fh                    ;Only hours remain in AX
  302.         MOV     DI,OFFSET REP_F_HH        ;Point so we can mov to hour field
  303.         Call    Convert_Dec_ASCII         ;Convert 2 decimal digits to ASCII
  304.  
  305. ;Minutes
  306.         MOV     AX,DX                     ;Restore copy of the time
  307.         MOV     CL,5
  308.         ROR     AX,CL                     ;Minutes are rightmost in AX
  309.         AND     AX,3Fh                    ;Mask off minutes
  310.         MOV     DI,OFFSET REP_F_MI        ;Point to minutes in output field
  311.         Call    Convert_Dec_ASCII         ;Convert 2 decimal digits to ASCII
  312.  
  313. ;Seconds
  314.         MOV     AX,DX                     ;Restore copy of the time
  315.         AND     AX,1Fh                    ;Only seconds remain after MASKing
  316.         ROL     AX,1                      ;Multiply secs by 2
  317.         MOV     DI,OFFSET REP_F_SS        ;Point so we can mov to hour field
  318.         Call    Convert_Dec_ASCII         ;Convert 2 decimal digits to ASCII
  319.  
  320.  
  321. ; Check if this file is a directory entry rather than a file
  322.         TEST    DTA_F_attr,00010000B      ;Check directory bit of file attribute
  323.         JZ      Open_the_File             ;If not continue with normal process
  324.  
  325. ; Do special handling for directory entries (rather than file entries):
  326.         MOV     DI,offset REP_CHK_Sum     ;prep to place msg in chk sum field
  327.         MOV     AX,'iD'                   ;Store "Dir." in report record
  328.         STOSW                             ;  to indicate this is a directory
  329.         MOV     AX,'.r'                   ;  entry rather than a normal file.
  330.         STOSW
  331.         MOV     CX,5                      ;Now blank fill the remainder of
  332.         MOV     AL,' '                    ;    the REPort record chk val 2
  333.         REP     STOSB
  334.         JMP     Write_REP_Rec             ;Skip rest of processing and go print
  335.                                           ;   this dir entry + find next file
  336.  
  337. ; Do special handling for files which would not open or got an I/O error:
  338. ; SI points to 9 char message containing type of error which occured
  339. Error_on_File:                          ;Place error msg in chkval1+2 fields
  340.         MOV     DI,offset REP_CHK_Sum     ;prep to place msg in chk val 1 field
  341.         MOV     CX,9                      ;Transfer 9 characters
  342.         REP     MOVSB                     ;Copy error msg into report record
  343.         MOV     File_Err_Flag,'Y'         ;Indicate we encountered a file error
  344.         JMP     Write_REP_Rec             ;Skip rest of processing and go print
  345.  
  346. ; --------------;
  347. ; Open the file ;
  348. ; --------------;
  349. Open_the_File:
  350.         MOV     DX,offset DTA_F_name      ;point to file name in DTA
  351.         MOV     AX,3D00h                  ;DOS open file (handle) for read cmnd
  352.         INT     21h                       ;invoke DOS
  353.         JNC     Continue_Open             ;If no errors continue processing
  354. ; This open should never fail...(OS2 can have files open which will cause fail)
  355.         MOV     SI,OFFSET Open_Err_Msg    ;Error message to place in REP_rec
  356.         JMP     SHORT Error_on_File       ;Finish processing this file with
  357.                                           ;  a report that open failed
  358. Continue_Open:
  359.         MOV     BX,AX                     ;Save file handle
  360.         XOR     BP,BP                     ;zero out (clear) EOF indicator
  361.                                           ; zero indicates more info to read.
  362.  
  363. ; -------------------------------------------;
  364. ; Initialize check values 1 + 2 for each file;
  365. ; -------------------------------------------;
  366. Init_CHK_XOR_Sums:
  367.         MOV     DI,BP                     ;Zero check sum init for each file
  368.         MOV     DX,BP                     ;Zero check value 2 (XOR value)
  369.  
  370.  
  371. ; ----------------------------------------------------------------;
  372. ; START OF LOOP TO READ AND SCAN RECORDS                          ;
  373. ; ----------------------------------------------------------------;
  374. ; REGISTER USAGE CONVENTIONS IN READ_FILE LOOP:                   ;
  375. ;                                                                 ;
  376. ; AL - Each new character read into this register                 ;
  377. ; BP - EOF (End Of File) indicator (flag)                         ;
  378. ; BX - Contains current file handle                               ;
  379. ; CX - number of chars read in -decreasing counter                ;
  380. ; DI - Contains check value 1 for this file (CHKSUM)              ;
  381. ; DX - Check value 2 for file and periodically start of buffer    ;
  382. ; SI - index pointing into file BUFFER                            ;
  383. ; ----------------------------------------------------------------;
  384. Read_File:
  385.         PUSH    DX                        ;Save the check value 2 (XOR sum)
  386.         MOV     DX,OFFSET Buffer          ;INPUT BUFFER
  387.         MOV     SI,DX                     ;SI is for BUFFER reads later
  388.         MOV     CX,0FC00h                 ;MAX # of bytes to read
  389.         MOV     AH,3Fh                    ;Setup to read from file
  390.         INT     21h                       ;Call DOS
  391.         POP     DX                        ;Resume using DX for chk val 2 (XOR)
  392.         JNC     Read_was_OK               ;Did an error occur on read?
  393.         MOV     AH,3Eh                    ; NO, so issue DOS close file func
  394.         INT     21h                       ;    Let DOS close file
  395.         MOV     SI,OFFSET Read_Err_Msg    ;    Point to error message to write
  396.         JMP     SHORT Error_on_File       ;    write err msg on REP_REC
  397. Read_was_OK:
  398.         OR      AX,AX                     ;Check if ax=0 no records read
  399.         JZ      Done_reading              ;If no records, close this file..
  400.         CMP     AX,CX                     ;See of max number or records read
  401.         JE      Skip_EOF_ind              ;If we have compltly filled buffer
  402.         MOV     BP,SP                     ;  Else put EOF indicator in BP
  403. Skip_EOF_ind:                             ;Jump here to skip setting EOF
  404.         MOV     CX,AX                     ;SAVE # of BYTES read in CX
  405.         JCXZ    Done_reading              ;Quit if nothing read
  406.         XOR     AH,AH                     ;Zero upper part of AX for addition
  407.  
  408. ; Innermost read char loop  - keep this fast!
  409. NEXT_CHAR:
  410.         LODSB                             ;Get char into AL
  411.         XOR     DL,AL                     ;cumulative chk val 2 (XOR) into DX
  412.                                           ;following instr modified by /2 parm
  413. ROL_op: ROL     DX,1                      ;Keep shifting to XOR sum to left
  414.                                           ;following instr modified by /1 parm
  415. ADD_op: ADD     DI,AX                     ;cumulative check sum (check value 1)
  416.         LOOP    NEXT_CHAR                 ;CONTINUE SCANNING CHARS UNTIL EOB
  417.  
  418.         OR      BP,BP                     ;Check EOF indicator (=77h if EOF)
  419.         JNZ     Done_reading              ;IF EOF, quit this file...
  420.         JMP     SHORT Read_File           ;TRY TO READ SOME MORE
  421.  
  422.  
  423. Done_reading:                             ;Come here on EOF or error reading
  424.         MOV     AH,3Eh                    ;Prepare to close the file
  425.         INT     21h                       ;Let DOS close file
  426.  
  427.         Call    Convert_Sums_for_Display  ;Convert check values for display
  428.  
  429.         ADD     Tot_CHK_Sum,BX            ;Total the check val1s for all files
  430.         ADD     Tot_XOR_Sum,CX            ;Total the chk val2s for all files
  431.  
  432. ;---------------;
  433. ; PRINT REP_REC ;
  434. ;---------------;
  435. Write_REP_Rec:
  436.         MOV     DX, offset REP_rec        ;prepare to print REPort record
  437.         MOV     CX,REP_Rec_Len            ;51 chars in REP_rec
  438.         MOV     BX,1                      ;Handle for std REPort device
  439.         MOV     AH,40h                    ;DOS display string function
  440.         INT     21h
  441.  
  442. ;-------------------------------;
  443. ; Search for next matching file ;
  444. ;-------------------------------;
  445. Find_Next_File:
  446.         MOV     AH,4Fh                    ;Search for next matching file
  447.         INT     21h                       ;Do search
  448.         JC      Finish_Processing         ;If no more matches, terminate.
  449.         JMP     Format_File_Info          ;If no errors, open new file
  450.  
  451. Finish_Processing:                        ;Else, Prepare to terminate
  452.         CMP     Files_Found,'Y'           ;Did we check at least one file?
  453.         JE      Totals_Processing         ;  If so, go do totals processing
  454.         JMP     No_Files_Found            ;  Else terminate with 04 Err lvl
  455.  
  456. Totals_Processing:
  457.         CMP     Totals_Wanted,'Y'         ;Check if user requested totals line
  458.         JNE     Check_drive_path_changes  ;If not then just quit
  459.  
  460. ; Move cumulative file totals into REP_REC for display
  461.         MOV     DI,Tot_CHK_Sum            ;Prepare cumulative totals for dsply
  462.         MOV     DX,Tot_XOR_Sum
  463.         Call    Convert_Sums_for_Display  ;Place cum totals in REPort record
  464.         MOV     DI, offset REP_F_Name     ;prepare to place "File totals:"
  465.         MOV     SI, offset Totals_MSG     ;      message in place of file name.
  466.         MOV     CX,12                     ;12 characters of name to copy
  467.         REP     MOVSB                     ;Copy the literal into filename field
  468.         MOV     word ptr [REP_F_Size-1],CRLF ;Car retrn LF to terminate record
  469. ; Write the cumulative file totals line
  470.         MOV     DX, offset REP_rec
  471.         MOV     AH,40h
  472.         MOV     BX,1                      ;File handle of std output
  473.         MOV     CX,24                     ;print 24 chars of REPrec only
  474.         INT     21h                       ;Actually write out the totals line
  475.  
  476. Check_drive_path_changes:
  477.         Call    Restore_Original_Path     ;Set back to original path if changd
  478.         Call    Restore_Original_Drive    ;Set back to original drive if changd
  479.  
  480.         MOV     AL,00h                    ;Plan on termination with 0 errlvl
  481.         CMP     File_Err_Flag,'Y'         ;Did we get a file I/O error ?
  482.         JNE     End_Execution             ;  If not, term with 0 error level
  483.         MOV     AL,08h                    ;  Else, terminate with 8 error level
  484.  
  485. End_Execution:                            ;Successful termination of program
  486.         MOV     AH,4Ch                    ;terminate with error level in AL
  487.         INT     21h
  488.  
  489.         SUBTTL  General Purpose subroutines
  490.         PAGE
  491. ;******************************************************************************;
  492. ;**   General purpose subroutines follow                                     **;
  493. ;******************************************************************************;
  494.  
  495. Convert_Sums_for_Display:
  496. ;------------------------------------------------------------------------------;
  497. ; Convert Check values (1 + 2) to ASCII hex characters and store in REP_REC    ;
  498. ;------------------------------------------------------------------------------;
  499. ;Input: DI contains check value 1 (16 bit checksum type field)                 ;
  500. ;       DX contains 16 bit check value 2 (hash type XOR field)                 ;
  501. ;Output: REP_Rec will contain display versions of both check values.           ;
  502. ;        AX,BX,CX,DX and DI will be corrupted. BX,CX will contain CHK val 1 + 2;
  503. ;------------------------------------------------------------------------------;
  504.         MOV     BX,DI                     ;save checksum (check value 1) in BX
  505.         MOV     CX,DX                     ;save XOR (chk value 2) in CX
  506.         MOV     DL,1                      ;DX<>0 turns leading 0 suppression off
  507.         MOV     DI,OFFSET REP_CHK_Sum     ;Field for hex ASCII characters
  508.         MOV     AH,BH                     ;Upper byte of chk val 1 (checksum)
  509.         CALL    Convert_Hex_ASCII         ;Convert to 2 hex ASCII characters
  510.         MOV     AH,BL                     ;Lower byte of checksum
  511.         CALL    Convert_Hex_ASCII         ;Convert to 2 hex ASCII characters
  512.         INC     DI                        ;Skip over space + into chkval2 (XOR)
  513.         MOV     AH,CH                     ;Upper byte of chkval2 (XOR)
  514.         CALL    Convert_Hex_ASCII         ;Convert to 2 hex ASCII characters
  515.         MOV     AH,CL                     ;lower byte of chkval2 (XOR)
  516.         CALL    Convert_Hex_ASCII         ;Convert to 2 hex ASCII characters
  517.         RET
  518.  
  519.  
  520. ;------------------------------------------------------------------------------;
  521. ;   CONVERT HEX ASCII   -  Convert hex byte (8 bits) to 2 ascii display bytes  ;
  522. ;------------------------------------------------------------------------------;
  523. Convert_Hex_ASCII:
  524.       CALL      Convert_Hex_Nyble_ASCII   ;Convert nyble (4 bits) to hex ASCII
  525.       CALL      Convert_Hex_Nyble_ASCII   ;Convert nyble (4 bits) to hex ASCII
  526.       RET                                 ;RETURN to caller
  527.  
  528. ;------------------------------------------------------------------------------;
  529. ; CONVERT HEX NYBLE ASCII - Convert hex digit (4 bits) to 1 ascii display byte ;
  530. ;------------------------------------------------------------------------------;
  531. ;Input: AH upper 4 bits contain hex to be converted. DI points to report record;
  532. ;       DX should be set to zero for leading zero suppression.                 ;
  533. ;Output: 1 byte in report record will contain ASCII display code of HEX byte.  ;
  534. ;       AH be shifted 4 bits to left. AL will contain ASCII version of HEX.    ;
  535. ;       DI will be incremented twice. DX will be = SP if nonzero output        ;
  536. ;------------------------------------------------------------------------------;
  537. Convert_Hex_Nyble_ASCII:
  538.         XOR     AL,AL                     ;Zero out AL
  539.         ROL     AX,1                      ;Move half byte (hex digit) into AL
  540.         ROL     AX,1
  541.         ROL     AX,1
  542.         ROL     AX,1                      ;AL now contains a hex digit
  543.         OR      AL,AL                     ;Is this a zero?
  544.         JE      Leading_Zero_check        ;If so check if this is leading zero
  545.         MOV     DX,SP                     ;Set non 0 to indicate non 0 found
  546. Continue_hex_check:
  547.         CMP     AL,9                      ;Is digit 0 to 9 or A to F ?
  548.         JA      Hex_alpha_digit           ;If hex A to F, do special conversion
  549.         ADD     AL,'0'                    ;Convert hex digit to ascii display
  550.         STOSB                             ;store in display field (REP_F_size)
  551.         RET
  552. Hex_alpha_digit:                          ;Convert hex A to F to ASCII display
  553.         ADD     AL,'A'-10
  554.         STOSB                             ;store in display field (REP_F_size)
  555.         RET
  556. Leading_Zero_Check:                       ;Check and blank out leading zeros
  557.         OR      DX,DX                     ;Have non zeros been detected yet?
  558.         JNZ     Continue_hex_check        ;If so then do normal processing
  559.         MOV     AL,' '                    ;Else put out a leading blank
  560.         STOSB
  561.         RET
  562.  
  563.  
  564. ;------------------------------------------------------------------------------;
  565. ;   CONVERT DEC ASCII   -  Convert 2 decimal digits to 2 ascii display bytes   ;
  566. ;------------------------------------------------------------------------------;
  567. ;Input: BL contains 10. AX contains decimal number 0 to 99 to be converted.    ;
  568. ;       DI points to destination to store result                               ;
  569. ;       Both digits will be stored at location pointed to by DI.               ;
  570. ;------------------------------------------------------------------------------;
  571. Convert_DEC_ASCII:
  572.         DIV     BL                        ;Divide by 10
  573.         ADD     AX,'00'                   ;Convert to ASCII digits
  574.         STOSW
  575.         RET
  576.  
  577.  
  578. ;------------------------------------------------------------------------------;
  579. ;   Restore orginal drive - if disk changed, set back to original disk.        ;
  580. ;------------------------------------------------------------------------------;
  581. Restore_Original_Drive:                   ;Set back to original drive if changd
  582.         CMP     Drive_Spec_Present,'Y'    ;Did user overide drive?
  583.         JNE     Restore_Drive_RET         ;If not then return to caller
  584.         MOV     DL,Old_disk               ;get original drive
  585.         MOV     AH,0Eh                    ;Set current drive function
  586.         INT     21h
  587. Restore_Drive_RET:
  588.         RET
  589.  
  590. ;------------------------------------------------------------------------------;
  591. ;   Restore orginal path - if path changed, set back to original disk.         ;
  592. ;------------------------------------------------------------------------------;
  593. Restore_Original_Path:                    ;Set back to orignl path if changed
  594.         CMP     Path_Present,'Y'          ;Did user overide path (Directory)
  595.         JNE     Restore_Path_RET          ;If not, return to caller
  596.         MOV     AH,3Bh                    ;Change current directory function
  597.         MOV     DX,offset Old_path        ;Original path
  598.         INT     21h                       ;Set path back to original
  599. Restore_Path_RET:
  600.         RET
  601.  
  602.         SUBTTL  Definition of Data structures
  603.         PAGE
  604. ;******************************************************************************;
  605. ;**   Definition of Data areas follow                                        **;
  606. ;******************************************************************************;
  607. File_Err_Flag DB  'N'                     ;='Y' if a file had open or read error
  608. Open_Err_Msg  DB  'Open fail'
  609. Read_Err_Msg  DB  'Read fail'
  610. REP_Rec       EQU  $                      ;Name for the entire REPort record
  611. REP_F_Name    DB   12 DUP (' ')           ;12 spaces reserved for filename
  612.               DB   ' '
  613. REP_CHK_Sum   DB   4  DUP ('0')           ;Check value 1 (chksum): 4 hex digits
  614.               DB   ' '
  615. REP_XOR_Sum   DB   4  DUP ('0')           ;Check value 2 (XOR) - 4 hex digits
  616.               DB   ' '
  617. REP_F_Size    DB   8 DUP ('0')            ;Size of file: 8 Hex digits
  618.               DB   ' '
  619. REP_F_MM      DB   'MM'                   ;Date of last file update:
  620.               DB   '/'
  621. REP_F_DD      DB   'DD'
  622.               DB   '/'
  623. REP_F_YY      DB   'YY'
  624.               DB   ' '
  625. REP_F_HH      DB   'HH'                   ;Time of last file update
  626.               DB   ':'
  627. REP_F_MI      DB   'MI'                   ;MInutes
  628.               DB   ':'
  629. REP_F_SS      DB   'SS'
  630.               DB   CR,LF                  ;End of REP_Rec (REPort record) descr
  631.  
  632. Old_Path      DB   '\'                    ;Force 1st char of save area to = '\'
  633.               DB   64 DUP (0)             ;Save area to restore original path
  634. Old_Disk      DB   0                      ;Save area for original drive spec
  635. Drive_Spec_Present DB  0                  ;Set = to "Y" if drive spec present
  636. Path_Present  DB   0                      ;Set = to "Y" if path specified
  637. Totals_wanted DB   0                      ;"Y" if totals desired on report
  638. Tot_CHK_Sum   DW   0                      ;total of all chk val 1s (all files)
  639. Tot_XOR_Sum   DW   0                      ;total of all check value 2s
  640. Totals_MSG    DB   'Total======>'
  641. Ignore_F_Name DW   '  '                   ;ignore file names starting with this
  642. Files_Found   DB  'N'                     ;Indicates if any files check at all
  643.         SUBTTL  INIT data and code which is also input BUFFER
  644.         PAGE
  645. ;******************************************************************************;
  646. ;**   Definition of file buffer Data areas and code follow:                  **;
  647. ;** All the following storage will be overlaid when records are read in      **;
  648. ;******************************************************************************;
  649.  
  650. Buffer        label  byte                 ;All storage + code following is in
  651.                                           ; the input file buffer.
  652.                                           ; address must be less than 3F0 hex.
  653.                                           ; Actual max is 3C0 to leave room
  654.                                           ; for the stack.
  655.  
  656. ; ----------------------------------------------------------------------------;
  657. ; Initialization code - parse parms + put out msgs and find intial file match ;
  658. ; ----------------------------------------------------------------------------;
  659. Parse_parms_Displ_Header:                 ;Parse input parameters + print header
  660.         MOV     SI,80h                    ;Parameter area in PSP
  661.         MOV     CL,[SI]                   ;Get # of chars in input parm
  662.         XOR     CH,CH                     ;Clear upper byte of char count
  663.         OR      CL,CL                     ;Check for 0 chars (NO INPUT)
  664.         MOV     BP,128                    ;Error level code for syntax error
  665.         JZ      Display_Syntax_Msg        ;IF no parms, put out help information
  666.         INC     SI                        ;Point to 1st character
  667.         CLD                               ;FORWARD DIRECTION
  668. ;
  669. Del_Spaces:
  670.         LODSB                             ;Get byte at DS:SI and inc SI
  671.         CMP     AL,' '                    ;Is it a space?
  672.         JNE     Set_File_names            ;If not we have a file name..
  673.         LOOP    Del_Spaces                ;Cont checking until last character
  674.         JMP     SHORT Display_Syntax_Msg  ;Explain syntax to user
  675. Syntax_Err_Exit:                          ;Come here on syntax error
  676.         MOV     AH,09h                    ;DOS display string function
  677.         INT     21h
  678.         CALL    Wait_For_Key              ;Beep + force user to hit a key{
  679. Display_Syntax_Msg:
  680.         MOV     DX, OFFSET Syntax_Msg     ;Prepare ERROR Message
  681.         MOV     AH,09h                    ;DOS display string function
  682.         INT     21h
  683.         Call    Restore_Original_Drive    ;Set back to original drive if changd
  684.         MOV     AX,BP                     ;Put error level in AL from BP
  685.         MOV     AH,4Ch                    ;   terminate with errorlevel in AL
  686.         INT     21h
  687.  
  688. ;---------------------------------------------------------------------------;
  689. ; Conventions for command line parsing:                                     ;
  690. ;   SI points to next char to be checked in the parm field at DS:80         ;
  691. ;   CX is count of characters left to be scanned                            ;
  692. ;   BP points to start of filespec for find next processing                 ;
  693. ;---------------------------------------------------------------------------;
  694.  
  695. ;----------------------------------------;
  696. ; Parse file spec and xfer in msg field  ;
  697. ;----------------------------------------;
  698. Set_File_Names:
  699.         CMP     BYTE PTR [SI],':'         ;Check for presence of drive spec
  700.         JNZ     Read_file_spec
  701.         AND     AL,5Fh                    ;Capitalize drive letter
  702.         SUB     AL,'A'                    ;Convert to numeric form
  703.         MOV     DL,AL                     ;Save a copy of numeric drive spec
  704.         MOV     Drive_spec_present,'Y'    ;Indicate user is overriding drive
  705.         MOV     AH,19h                    ;DOS get current drive function
  706.         INT     21h
  707.         MOV     Old_disk,AL               ;Save current disk
  708.         MOV     AH,0Eh                    ;DOS select disk function
  709.         INT     21h                       ;Set to user specified drive
  710.         JNC     Good_Disk_Specified       ;Was the disk drive specified OK?
  711.         JMP     Invalid_Path              ;  If drive specified is invalid..
  712. Good_Disk_Specified:                      ;  Drive is valid
  713.         ADD     SI,2                      ;adjust pointers and
  714.         SUB     CX,2                      ;      counters to skip drive spec
  715.  
  716. Read_file_spec:
  717.         DEC     SI                        ;point back to 1ST letter of filespec
  718.         MOV     BP,SI                     ;Save a copy of filespec start
  719.         MOV     DI, offset User_File_Spec ;prep to transfer file name to msg
  720.  
  721. Scan_To_File_Spec_End:
  722. ;       start scanning the file specification and transfer into output field
  723.         LODSB                             ;Get next char of file spec
  724.         CMP     AL,' '                    ;check valid separator character
  725.         JBE     file_spec_end_found
  726.         CMP     AL,'/'                    ;check for valid separator
  727.         JE      file_spec_end_found
  728.         STOSB                             ;Store char as part of User_file_spec
  729.         LOOP    Scan_To_File_Spec_End
  730.         INC     SI                        ;Adjust BX if no separator char found
  731.  
  732. File_Spec_End_Found:
  733.         MOV     BX,SI
  734.         DEC     BX                        ;= next char loc after filespec
  735.         MOV     BYTE PTR [BX],00          ;zero terminate the filespec: ASCIIZ
  736.         PUSH    AX                        ;Save last char examined
  737.         MOV     AX,CRLF                   ;Put out carriage return line feed
  738.         STOSW                             ;  combination as a single word
  739.         MOV     AL,LF                     ;Include extra line feed
  740.         STOSB
  741.         POP     AX                        ;Restore last character examined
  742. Check_parm_chars_left:                    ;Check if enough chars left for a parm
  743.         CMP     CX,01                     ;Check if we're out of chars to scan
  744.         JA      Parm_Scan                 ;  if not continue chcking for /parms
  745.         JMP     Check_for_DIR             ;  If so, skip ahead to directory proc
  746. Parm_Scan:                                ;Check for presence of a /_ parm
  747.         CMP     AL,'/'                    ;check for "/" parm character
  748.         JE      Parm_found
  749.         CMP     AL,' '                    ;check for blanks
  750.         JNE     Unrecog_parm              ;If other than blank its illegal...
  751.         LODSB                             ;Keep checking next character
  752.         LOOP    Parm_Scan
  753.         JMP     short Check_for_DIR       ;see if directory incl in filespec
  754.  
  755. Parm_Found:                               ;Check if parm is valid
  756.         DEC     CX                        ;Adjust chars remaining counter
  757.         JCXZ    Unrecog_parm              ;IF no chars left then parm is invalid
  758.         LODSB                             ;Get next char
  759.         DEC     CX                        ;Adjust chars remaining counter
  760.         CMP     AL,'2'                    ;Is it alternate XOR "/2" parm?
  761.         JE      X2_parm                   ;XOR:chk val2 parm detected
  762.         CMP     AL,'1'                    ;Is it alternate Check Sum "/1" parm?
  763.         JE      C1_parm                   ;/1 alternate chk val 1 parm detected
  764.         AND     AL,5Fh                    ;Capitalize char
  765.         CMP     AL,'T'                    ;Is it the "Totals wanted" parm?
  766.         JE      T_parm                    ;T parameter detected
  767.         CMP     AL,'D'                    ;Is it Directory display parm?
  768.         JE      D_parm                    ;D parameter detected..
  769.         CMP     AL,'I'                    ;Is it Ignore file parm?
  770.         JE      I_parm                    ;I parameter detected.. else its...
  771. Unrecog_parm:                             ; an illegal paramter:
  772.         MOV     DX, offset Bad_Parm_MSG   ;indicate illegal parm was found
  773.         MOV     BP,128                    ;Error level code for syntax error
  774.         JMP     Syntax_Err_Exit                  ;terminate with error level set
  775.  
  776. T_parm:
  777.         MOV     Totals_Wanted,'Y'         ;Indicate users wants total line
  778.         LODSB                             ;Keep checking next character
  779.         JMP     SHORT Check_Parm_chars_left     ;Check for additional parms
  780.  
  781. X2_parm:                                  ;/2 parm
  782.         MOV     WORD PTR [ROL_op],0CAD1h  ;patch ROL op code into ROR DX,1 op
  783.         LODSB                             ;Keep checking next character
  784.         JMP     SHORT Check_Parm_chars_left     ;Check for additional parms
  785.  
  786. C1_parm:                                  ;/1 parm (alternate chksum)
  787.         MOV     WORD PTR [ADD_op],0C729h  ;patch ADD op code into SUB DI,AX op
  788.         LODSB                             ;Keep checking next character
  789.         JMP     SHORT Check_Parm_chars_left     ;Check for additional parms
  790.  
  791. D_parm:
  792.         MOV     WORD PTR [File_Attrib],0017h ;Change file attrib to incl DIRs
  793.         LODSB                                ;Keep checking next character
  794.         JMP     SHORT Check_Parm_chars_left  ;Check for additional parms
  795.  
  796. I_parm:
  797.         CMP     CX,03                     ;We must have at least 3 chars left
  798.         JB      Unrecog_parm              ;If not, this is a bad parameter
  799.         LODSB                             ;Check next character
  800.         CMP     AL,':'                    ;  it should be ':'
  801.         JNE     Unrecog_parm              ;If not, its bad parm time again..
  802.         SUB     CX,03                     ;Adjust chrs remaining counter
  803.         LODSW                             ;Get file prefix to ignore
  804.  
  805. ;     Now capitalize the file name prefix, only if lower case alphabetic
  806.         CMP     AL,'a'                    ;could this be a lower case alpha?
  807.         JB      Check_2nd_char            ;If not go ahead and check other char
  808.         CMP     AL,'z'                    ;could this be a lower case alpha?
  809.         JA      Check_2nd_char            ;If not go ahead and check 2nd char
  810.         AND     AL,5Fh                    ;Bump character into uppercase
  811. Check_2nd_char:                           ;Now check the 2nd file ignore char
  812.         CMP     AH,'a'                    ;could this be a lower case alpha?
  813.         JB      I_store                   ;If not go ahead and store the char
  814.         CMP     AH,'z'                    ;could this be a lower case alpha?
  815.         JA      I_store                   ;If not go ahead and store the char
  816.         AND     AH,5Fh                    ;Bump character into uppercase
  817.  
  818. I_store:
  819.         MOV     Ignore_F_Name,AX          ;Store file prefix (for ignore)
  820.         LODSB                             ;Keep checking next character
  821.         JMP     Check_Parm_chars_left     ;Check for additional parms
  822.  
  823. Invalid_path:
  824.         MOV     DX,offset Bad_path_MSG    ;Indicate problem with path
  825.         MOV     BP,64                     ;Errorlevel for bad drive or path
  826.         JMP     Syntax_Err_Exit           ;Display error msg + correct syntax
  827.  
  828. Check_for_DIR:                            ;See if PATH included in filespec
  829.         MOV     CX,BX                     ;End of filespec + 1
  830.         SUB     CX,BP                     ;Calc length of filespec
  831.         PUSH    CX                        ;Save length of filespec for use later
  832.         STD                               ;Prepare to scan filespec backwards
  833.         MOV     DI,BX                     ;Start from end
  834.         DEC     DI                        ;                of filespec
  835.         MOV     AL,'\'                    ;Scan filespec for presence of "\"
  836.         REPNE   SCASB                     ;Scan to last \ from end of filespec
  837.         CLD                               ;Reset direction flag to forward
  838.         JNZ     Display_Heading           ;IF, no path found in filespec
  839.         MOV     Path_Present,'Y'          ;Set flag to indicate path present
  840.         INC     DI                        ;Point to "\" character
  841.         MOV     BYTE PTR [DI],0           ;Zero terminate the PATH (clobber \)
  842.                                           ;Determine current directory
  843.         MOV     SI,offset Old_path+1      ;Place to store original directory
  844.         XOR     DL,DL                     ;Zero DL in order to use default drive
  845.         MOV     AH,47h                    ;Get current directory (path) func
  846.         INT     21h
  847.         JC      Invalid_path              ;IF function failed(will never happen)
  848. ; prepare to set to user's specified file path (directory)
  849.         MOV     DX,BP                     ;beginning of dir in parm area
  850.         CMP     DI,BP                     ;Is \ 1 and only compon of dir string?
  851.         JNE     Not_Root_Dir              ;If \ is only char, this is root dir
  852.         MOV     DX, offset Root_Dir       ;  so set directory to root directory
  853. Not_Root_Dir:
  854.         MOV     AH,3Bh                    ;Set current directory function
  855.         INT     21h
  856.         JC      Invalid_path              ;IF function failed
  857.         INC     DI                        ;Point to start of filename (path+1)
  858.         MOV     BP,DI                     ;Set new filename start (skip path)
  859.  
  860. ;----------------------------------------------------------------------------;
  861. ; Display the start message and the heading for the file list                ;
  862. ;----------------------------------------------------------------------------;
  863. Display_Heading:
  864.         MOV     DX,OFFSET Start_MSG       ;Put out main banner msg for output
  865.         MOV     AH,40h                    ;DOS DISPLAY STRING FUNCTION
  866.         MOV     CX,SM_End-Start_MSG       ;47 chars in start msg
  867.         MOV     BX,1                      ;Handle for std output device
  868.         INT     21h
  869.         MOV     DX,OFFSET User_File_Spec  ;Tell user what files we're checking
  870.         MOV     AH,40h                    ;DOS write file funct (std output)
  871.         POP     CX                        ;Get length of filespec
  872.         ADD     CX,3                      ;add extra chars to length (CRLF LF)
  873.         INT     21h
  874.         MOV     DX,OFFSET Header_MSG      ;Put out header message for output
  875.         MOV     AH,40h                    ;DOS DISPLAY STRING FUNCTION
  876.         MOV     CX,149                    ;total of 149 chars in header
  877.         INT     21h
  878.  
  879. ;----------------------------------------------------------------------------;
  880. ; Find first occurance of a file to match the possible wildcards in filespec ;
  881. ;----------------------------------------------------------------------------;
  882. Find_First_File:
  883.         MOV     DX,BP                     ;DX points to filename
  884.         MOV     AH,4Eh                    ;DOS find first command (use 80H DTA)
  885.         MOV     CX,File_attrib            ;Set file attrib
  886.         INT     21h                       ;Invoke DOS
  887.         JNC     Done_FFF                  ;If no carry, then all is OK..
  888.  
  889. No_files_Found:                           ;Come here if no files matched
  890.         Call    Restore_Original_Path     ;Set back to original path if changd
  891.         Call    Restore_Original_Drive    ;Set back to original drive if changd
  892.         MOV     AX,4C04h                  ;   terminate with 04 error level
  893.         INT     21h
  894.  
  895. Done_FFF:
  896.         RET
  897.  
  898. ;---------------------------------------------------;
  899. ; W A I T   F O R   K E Y                           ;
  900. ;---------------------------------------------------;
  901. ; 1) Send out a BEEP                                ;
  902. ; 2) Determine screen attribute (screen colors)     ;
  903. ; 3) Determine what line cursor is on               ;
  904. ; 4) Put out message to hit any key on that line    ;
  905. ; 5) Wait for any keypress                          ;
  906. ; 6) Erase message using current screen attribute   ;
  907. ; 7) Position cursor back at start of current line. ;
  908. ; --------------------------------------------------;
  909. ; *** ALL REGISTERS MAY BE CORRUPTED EXCEPT AX  *** ;
  910. ; --------------------------------------------------;
  911. Wait_For_Key:                             ;Force user to notice error
  912.         PUSH    AX                        ;Save needed register
  913. ; Produce a beep to alert the user:  (use  BIOS TTY func to write an ASCII BELL)
  914.         MOV     AX,0E07h                  ;BIOS func (0Eh) to write (07H) beep
  915.         XOR     BH,BH                     ;Select page zero for output
  916.         INT     10h                       ;BIOS video function (0Eh=write char)
  917.  
  918. ;Find out what attribute is being used for display
  919.         MOV     AH,08h                    ;read attrib + char function
  920.         INT     10h                       ;Call BIOS
  921.         PUSH    AX                        ;Save AH=attribute byte
  922.  
  923. ;Find out what line the cursor is on
  924.         MOV     AH,03h                    ;Read cursor position function
  925.         INT     10h                       ;BIOS video services
  926.         PUSH    DX                        ;DH contains row (line #) Save it!
  927.  
  928. ; Position cursor to current line + column 28: (TO BIOS  row 27)
  929.         MOV     AH,02                     ;BIOS int 10h set cursor position func
  930.         XOR     BH,BH                     ;Set page to zero
  931.                                           ;DH contains current row
  932.         MOV     DL,1Bh                    ;Set cursor current row and col 27
  933.         INT     10h                       ;BIOS video services
  934.  
  935. ; Put -Hit any key- message out with inverse video attribute type on
  936. ;       XOR     BH,BH                     ;Set page to zero  (BH is still 0)
  937.         MOV     BL,0F0h                   ;Inverse video attribute
  938.         MOV     CX,1                      ;Character count
  939.         MOV     SI,offset Hit_Key_Msg     ;The hit-any-key message
  940. Display_next_video_char:
  941.         MOV     AH,09h                    ;BIOS int 10h write attrib + char func
  942.         LODSB                             ;Get next character for output
  943.         PUSH    SI                        ;Save SI (int 10h may corrupt it)
  944.         INT     10h                       ;Put character and attribute out
  945.         INC     DX                        ;Advance cursor position
  946.         MOV     AH,02                     ;Adv cursor function
  947.         INT     10h                       ;   advance the cursor (BIOS)
  948.         POP     SI                        ;Restore saved SI
  949.         CMP     SI,offset Hit_key_Msg_end ;are we at end of message?
  950.         JB      Display_next_video_char   ;  If not get next char for display
  951.                                           ;  Else, wait for key press by user
  952. ; Wait for user to hit any key
  953.         XOR     AX,AX
  954.         INT     16h                       ;Wait for user to hit a key
  955.  
  956. ; Erase HIT ANY KEY message
  957.         POP     DX                        ;DH=current line number
  958.         POP     BX                        ;BH=user's screen attribute
  959.         MOV     AH,06h                    ;INIT window function
  960.         XOR     AL,AL                     ;Zero AL to clear window
  961.         MOV     CH,DH                     ;Current row (y coor upr lft)
  962.         MOV     CL,00                     ;Start in first char position
  963.         MOV     DL,79                     ;Last char pos - blank entire line
  964.         INT     10h                       ;Blank out line
  965.  
  966. ; Position cursor to start of blanked line
  967.         MOV     AH,02                     ;BIOS int 10h set cursor position func
  968.         XOR     DL,DL                     ;DH=cur line, DL=0: first char pos
  969.         XOR     BX,BX                     ;Use video page zero
  970.         INT     10h                       ;BIOS video services
  971.         POP     AX                        ;Restore only need register
  972.         RET                               ;Return to caller
  973.  
  974.  
  975. ; --------------------------------------------------;
  976. ; Initialization DATA STORAGE                       ;
  977. ; --------------------------------------------------;
  978. Root_dir      DB  '\',0                      ;Zero terminated root dir string
  979. File_Attrib   DW  0007h                      ;File attribute (RO, hidden + sys)
  980. Start_MSG     DB  CR,LF,"CHKFILE 1.0 ",BOX," PCDATA TOOLKIT (c) 1990"
  981.               DB  " Ziff Communications Co.",CR,LF
  982.               DB  "PC Magazine ",BOX," Wolfgang Stiller.  Checking: "
  983. SM_End        LABEL  BYTE     ;End of the Start message
  984. Header_MSG    DB  'File Name + Check Check  File    Update   Update'
  985.               DB   CR,LF
  986.               DB  'Extension:  Val1: Val2:  Size:   Date:    Time:'
  987.               DB   CR,LF
  988.               DB  '----------   ---- ----   -----   ------   ------'
  989.               DB   CR,LF
  990. Bad_Path_MSG  DB  'Invalid path/drive.',CR,LF,'$'
  991. Bad_Parm_MSG  DB  'Unrecognized parameter detected.',cr,lf,lf,'$'
  992. Syntax_Msg    DB  "CHKFILE 1.0 ",BOX," PCDATA TOOLKIT Copyright (c) 1990"
  993.               DB  " Ziff Communications Co.",CR,LF
  994.               DB  "PC Magazine ",BOX," Wolfgang Stiller",CR,LF,CR,LF
  995.               DB  'CHKFILE will read all files which match the specified file '
  996.               DB  'name, reporting',CR,LF
  997.               DB  'two check values, plus DOS file size, date and time. This'
  998.               DB  ' information',CR,LF
  999.               DB  'can be used by CFcomp to validate file integrity.'
  1000.               DB   CR,LF,LF
  1001.               DB  'Syntax is: CHKFILE [d:] [path] filename [/D] [/I:zz] '
  1002.               DB  '[/T] [/1] [/2]',CR,LF,LF
  1003.               DB  '   "filename" specifies the files to check. Wild card'
  1004.               DB  ' characters such',CR,LF
  1005.               DB  '             as * or ? may be used.',CR,LF
  1006.               DB  '   "/D"      Display directory entries as well as files.'
  1007.               DB   CR,LF
  1008.               DB  '   "/I:aa"   Ignore all files which begin with the 2 '
  1009.               DB  'chars: aa.',CR,LF
  1010.               DB  '   "/T"      Totals line will be written.'
  1011.               DB   CR,LF
  1012.               DB  '   "/1"      Utilize an alternate check value1 algorithm.'
  1013.               DB   CR,LF
  1014.               DB  '   "/2"      Utilize an alternate check value2 algorithm.'
  1015.               DB   CR,LF,'$'
  1016.  
  1017. Hit_Key_MSG   DB   '-Hit any key-'
  1018. Hit_Key_MSG_end EQU  $
  1019. User_file_spec  EQU  $                ;User specified file spec to check
  1020. CSEG    EndS
  1021.         END     CHKFILE
  1022.